/*
 * FreeModbus Libary: STM32F4 Port
 * Copyright (C) 2006 Christian Walter <wolti@sil.at>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * File: $Id$
 */

/* ----------------------- System includes ----------------------------------*/
// #include "assert.h"

/* ----------------------- STM32F4 includes ----------------------------------*/
#include "stm32f4xx.h"
#include "stm32f4xx_usart.h"

/* ----------------------- Platform includes --------------------------------*/
#include "port.h"

/* ----------------------- Modbus includes ----------------------------------*/
#include "mb.h"
#include "mbport.h"

/* ----------------------- Defines ------------------------------------------*/
// master USART2 PD7
// slave USART6 PD1
#define MB_UART_DEV (USART6)
#define MB_UART_IRQ_CH (USART6_IRQn)
#define MB_UART_IRQHandler (USART6_IRQHandler)

/* ----------------------- Start implementation -----------------------------*/
BOOL xMBPortSerialInit(UCHAR ucPort, ULONG ulBaudRate, UCHAR ucDataBits, eMBParity eParity)
{
    (void)ucPort;
    (void)ucDataBits;

    BOOL xResult = TRUE;
    GPIO_InitTypeDef GPIO_InitStructure;
    USART_InitTypeDef USART_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;

    // 使能GPIO,USART时钟
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);  // 使能GPIO时钟
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);  // 使能GPIO时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART6, ENABLE); // 使能USART时钟
    USART_DeInit(USART6);                                  // 复位串口

    // GPIO端口设置
    // USART_TX(PC6)
    GPIO_PinAFConfig(GPIOC, GPIO_PinSource6, GPIO_AF_USART6); // 引脚复用映射
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;                 // 对应引脚
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;              // 复用功能
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;         // 速度50MHz
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;            // 推挽输出
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;              // 上拉
    GPIO_Init(GPIOC, &GPIO_InitStructure);                    // 初始化IO口
    // USART_RX(PC7)
    GPIO_PinAFConfig(GPIOC, GPIO_PinSource7, GPIO_AF_USART6); // 引脚复用映射
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;                 // 对应引脚
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;              // 复用功能
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;         // 速度50MHz
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;            // 推挽输出
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;              // 上拉
    GPIO_Init(GPIOC, &GPIO_InitStructure);                    // 初始化IO口

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; // 对应引脚
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // 速度50MHz
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;    // 推挽输出
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;      // 上拉
    GPIO_Init(GPIOD, &GPIO_InitStructure);            // 初始化IO口

    // USART NVIC 配置
    NVIC_InitStructure.NVIC_IRQChannel = MB_UART_IRQ_CH;      // IRQ中断源
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3; // 抢占优先级
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;        // 子优先级
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;           // IRQ通道使能
    NVIC_Init(&NVIC_InitStructure);

    // USART 初始化设置
    USART_InitStructure.USART_BaudRate = ulBaudRate; // 波特率

    switch (eParity)
    {
        case MB_PAR_EVEN:
            USART_InitStructure.USART_Parity = USART_Parity_Even;
            USART_InitStructure.USART_WordLength = USART_WordLength_9b;
            break;
        case MB_PAR_ODD:
            USART_InitStructure.USART_Parity = USART_Parity_Odd;
            USART_InitStructure.USART_WordLength = USART_WordLength_9b;
            break;
        case MB_PAR_NONE:
            USART_InitStructure.USART_Parity = USART_Parity_No;
            USART_InitStructure.USART_WordLength = USART_WordLength_8b;
            break;
    }

    USART_InitStructure.USART_StopBits = USART_StopBits_1;
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;

    USART_Init(MB_UART_DEV, &USART_InitStructure);      // 初始化串口
    USART_ITConfig(MB_UART_DEV, USART_IT_RXNE, ENABLE); // 开启中断
    USART_ITConfig(MB_UART_DEV, USART_IT_TC, ENABLE);   // 开启中断
    USART_Cmd(MB_UART_DEV, ENABLE);                     // 使能串口

    return xResult;
}

void vMBPortClose(void) {}

void xMBPortSerialClose(void) {}

void vMBPortSerialEnable(BOOL xRxEnable, BOOL xTxEnable)
{
    if (xRxEnable)
    {
        GPIO_ResetBits(GPIOD, GPIO_Pin_1);
        USART_ITConfig(MB_UART_DEV, USART_IT_RXNE, ENABLE);
    }
    else
    {
        GPIO_SetBits(GPIOD, GPIO_Pin_1);
        USART_ITConfig(MB_UART_DEV, USART_IT_RXNE, DISABLE);
    }

    if (xTxEnable)
    {
        GPIO_SetBits(GPIOD, GPIO_Pin_1);
        USART_ITConfig(MB_UART_DEV, USART_IT_TC, ENABLE);
        pxMBFrameCBTransmitterEmpty();
    }
    else
    {
        GPIO_ResetBits(GPIOD, GPIO_Pin_1);
        USART_ITConfig(MB_UART_DEV, USART_IT_TC, DISABLE);
    }
}

BOOL xMBPortSerialPutByte(CHAR ucByte)
{
    USART_SendData(MB_UART_DEV, ucByte);
    return TRUE;
}

BOOL xMBPortSerialGetByte(CHAR *pucByte)
{
    *pucByte = USART_ReceiveData(MB_UART_DEV);
    return TRUE;
}

void MB_UART_IRQHandler(void)
{
    if (USART_GetITStatus(MB_UART_DEV, USART_IT_RXNE) != RESET) /* USART_IT_RXNE */
    {
        pxMBFrameCBByteReceived();
        USART_ClearITPendingBit(MB_UART_DEV, USART_IT_RXNE);
    }

    if (USART_GetITStatus(MB_UART_DEV, USART_IT_ORE_RX) != RESET) // USART_IT_ORE_RX
    {
        MB_UART_DEV->SR;
        MB_UART_DEV->DR;
    }

    if (USART_GetITStatus(MB_UART_DEV, USART_IT_IDLE) != RESET) // USART_IT_IDLE
    {
        MB_UART_DEV->SR;
        MB_UART_DEV->DR;
    }

    if (USART_GetITStatus(MB_UART_DEV, USART_IT_TC) != RESET) // USART_IT_TC
    {
        pxMBFrameCBTransmitterEmpty();
        USART_ClearITPendingBit(MB_UART_DEV, USART_IT_TC);
    }
}
